#include "fireware_update_extr.h"
#include "string.h"
#include "stdlib.h"
#include "stmflash.h"
#include "gprs.h"
#include "stdio.h"
#include "usart.h"
#include "sys.h"
#include "wdg.h"

 

//当前固件版本号
const  u16   _CurVersion = CURRENT_FIRMWARE_VERSION;

//目标固件版本号
u16   _UpdateVersion;



//要升级总的报文包数
uint16 _TotalPackageCount = 0;      

//升级报文每包的字节数
uint16 _OnePackageSize = 0; 

//当前请求升级报文的序号
uint16 _ReqPackageIndex = 1;					/* 升级包序列号 */


UpdateConfig _UpdateConfig;

extern u16      _TimeOutCount; 

#define HIBYTE(w)           ((uint8)(((uint16)(w) >> 8) & 0xFF))

//函数声明
uint16 crc16h(char *ptr, uint32 len);
uint16 crc16l(char *ptr, uint32 len);
void StartUpdate(u8 updateVersion, const char * pstrImei, const  char * update_server_ip,const char * update_server_port);
void RequestNPackage(uint16 i);
void UpdateFinish(void);
void UpdateMessageHandle(H4Message *);
 
typedef enum tagUpdateState
{
	Start,
	ReceivePackInfo,
	ReceiveNPack,
	Finish,
	Idle,
	Exit
}enumUpdateState;

enumUpdateState _State=Start;
u8 _Mark[16] =  {0xAA, 0xAB, 0xAC, 0xAD, 0x9A, 0x9B, 0x9C, 0x9D, 0x8A, 0x8B, 0x8C, 0x8D, 0x7A, 0x7B,   0x7C, 0x7D};
/*************************************************
函数名称: StartUpdate
功    能: 开始升级
参    数: 无
返 回 值: 无
*************************************************/
void StartUpdate(u8 updateVersion, const char * pstrImei, const  char * update_server_dn,const char * update_server_port)
{

 
	uint32 u32Temp;
 
  UPDATA_HEADER *pHeader; 
	H4Message *pH4Message;
 
	DebugOut("- - - - - - - StartUpdate - - - - - - -\r\n");
  _UpdateVersion=updateVersion;
	PrepareConnect();

  printf("%s %s\r\n",update_server_dn,update_server_port);
	u32Temp = CIPSTART((uint8 *)update_server_dn, (uint8 *)update_server_port); // 
	
	printf("Connect update server:%d\r\n",u32Temp);

	if(u32Temp == 0)
	{
		 
		return; 
	}
 
	
  _State=Start;
	
	_TimeOutCount=0;
	while(1)
	{
		IWDG_Feed();
		switch(_State)
		{
			case Start:
				
				pH4Message=GetH4MessageBuffer(); 
			  pH4Message->Version=0;
			  pH4Message->MessageType=T_REQ_START;//请求升级报文
			  pH4Message->BodyLength=sizeof(UPDATA_HEADER);
			
			  PackH4MSGHead();
			
			  pHeader = (UPDATA_HEADER *)(pH4Message->HeadBodyData+MSGH4_HEAD_LENGTH);
			  sprintf(pHeader->IMEI, "%s",pstrImei ); 
			  pHeader->reqVer=updateVersion;
			  pHeader->curVer=_CurVersion; 
				printf("send update start request!\r\n");
				pH4Message= SendH4MsgToServerSync(pH4Message, 30); 				  
      	UpdateMessageHandle(pH4Message);  
				_TimeOutCount=0;
				break;
			case ReceivePackInfo:
					 
				_ReqPackageIndex = 1;           
				RequestNPackage(_ReqPackageIndex);
				_TimeOutCount=0;
				break;
			case ReceiveNPack:
					 
				++_ReqPackageIndex;
				RequestNPackage(_ReqPackageIndex);
				_TimeOutCount=0;
				break;
			case Finish:				 
				UpdateFinish();			
				DebugOut( "update success!,restart.\r\n");			
				IWDG_Feed();
				SoftReset();
			case Idle:
				if(_TimeOutCount>30)
					 _State=Exit;
				break;
			case Exit:
				return;
		}
	}
}



/*************************************************
函数名称: update_package_handle
功    能: 升级报文处理程序
参    数: char * data-升级报文缓冲区
返 回 值: TRUE-正确,FALSE-升级报文异常
*************************************************/
void UpdateMessageHandle(H4Message * pMessage)
{
 
 
	uint32	i;
  uint16  crc;
//	/* 服务器升级请求应答 */
  	SERVER_INFOACK_S	* p_server_info; 	
//	/* 服务器升级数据包 */
	SERVER_DATA_S		* p_server_data; 		
 
	
 
	 switch (pMessage->MessageType)
    {
		 case S_RES_INFO:
			 	//升级总体信息
				p_server_info = (SERVER_INFOACK_S *)(pMessage->HeadBodyData + MSGH4_HEAD_LENGTH);
		   
				/* 判断版本号是否正确 */
				if(_UpdateVersion==p_server_info->ReqVersion)   //如果版本号正确
				{
					_TotalPackageCount = p_server_info->TotalPackageCount;
					_OnePackageSize =  p_server_info->OnePackageSize ;

 
					DebugOut("start update,total package:%d,pakcate size:%d\r\n",_TotalPackageCount,_OnePackageSize);
		 
				   _State= ReceivePackInfo;
				}
        else
				{
					 DebugOut("UpdateVersion:%d     ResponseVersion:%d\r\n",_UpdateVersion, p_server_info->ReqVersion);
					_State=Exit;
					DebugOut("wrong version\r\n");
				}					
        break;		 
		 case S_RES_N_DATA:
			 //				//升级报文体
				p_server_data = (SERVER_DATA_S *)(pMessage->HeadBodyData + MSGH4_HEAD_LENGTH);
				
	 
					  DebugOut("system is updating,total package:%d,current package:%d,\r\n",_TotalPackageCount,p_server_data->pack_id);
		 
	        	crc = crc16h((char *)(p_server_data->data), _OnePackageSize);
		 
		         //DebugOut("local crc:%x  remote crc:%x\r\n",crc,p_server_data->crc);
		          if(p_server_data->crc!=crc)
							{
								DebugOut("CRC Error\r\n");
								_State=Exit;
							  break;
							}
 

						if(_ReqPackageIndex < _TotalPackageCount)	
						{
							//保存升级报文到FLASH中
							STMFLASH_Write(FIRMWARE_SAVE + (_ReqPackageIndex - 1) * _OnePackageSize, (uint16 *)p_server_data->data,  (_OnePackageSize >> 1));
						 		//如果不是最后一包，则请求包号+1			
							//RequestNPackage(num_update_bag);
							_State= ReceiveNPack;
						} 
						else if(_ReqPackageIndex == _TotalPackageCount)   
						{
							/* 保存最后一包数据 */
							STMFLASH_Write(FIRMWARE_SAVE + (_ReqPackageIndex - 1) * _OnePackageSize, (uint16 *)p_server_data->data,  (_OnePackageSize >> 1));
							
							 
							
							/* 保存固件程序长度 */
							i = _OnePackageSize * _TotalPackageCount;
							memcpy(_UpdateConfig.ValidMark,_Mark,sizeof(_Mark));
							_UpdateConfig.UpdateVersion=_UpdateVersion;		
							_UpdateConfig.CurVersion=_CurVersion;
							_UpdateConfig.NewFirmwireLen=i;
							
		 
							
							STMFLASH_Write(UPDATE_CFG_ADDR,  (uint16 *)(&_UpdateConfig),  (sizeof(_UpdateConfig) >> 1));
							
			 	 
							_State= Finish;
 
					
						 
						}								

		 
			 break;
    default:
			  _State=Idle;
        break;
    }
	
}

 
/******************************************************
* 名    称：void Send_Request_bag(uint16 i)
* 功    能：发送请求下载更新文件第i包
* 入口参数：uint16 i： 请求下载文件的包号
* 出口参数：无
* 返回值：无
* 说    明：无
* 调用方法：在终端收到更新文件的总包号和每包的字节数后，发送该报文		   			  
**********************************************************/
void RequestNPackage(uint16 i)
{
 
 
	SERVER_INFO_T * pData;
  H4Message* pH4Message=GetH4MessageBuffer();
	InitH4Message();
	pH4Message->Version=0;
	pH4Message->MessageType=T_REQ_N_DATA;//请求升级报文
	pH4Message->BodyLength=sizeof(SERVER_INFO_T);
	PackH4MSGHead();
	
	 pData = (SERVER_INFO_T *)(pH4Message->HeadBodyData+MSGH4_HEAD_LENGTH);
	 pData->sequence = i;	 
 //printf("request %d package\r\n",i);
  
	 //调用原有发送函数发送报文
	 pH4Message= SendH4MsgToServerSync(pH4Message, 30 ); 
	 UpdateMessageHandle(pH4Message);
 	 InitH4Message();
	
}
/******************************************************
* 名    称：void Send_Update_Finish(void)
* 功    能：发送下载更新文件完成
* 入口参数：无
* 出口参数：无
* 返回值：无
* 说    明：无
* 调用方法：在下载全部更新文件包后，发送该报文 		   			  
**********************************************************/
void UpdateFinish(void)
{
 
 
 H4Message* pH4Message=GetH4MessageBuffer();
 InitH4Message();
	pH4Message->Version=0;
	pH4Message->MessageType=T_REQ_END;//请求升级报文
	pH4Message->BodyLength=0;
	PackH4MSGHead();
	pH4Message= SendH4MsgToServerSync( pH4Message, 30 ); 
	UpdateMessageHandle(pH4Message);
 	 InitH4Message();
		
}
/******************************************************
* 名    称：uint16 crc16h(char *ptr, uint32 len)
* 功    能：CRC校验
* 入口参数：char *ptr-要校验字符串的缓冲区地址
				  uint32 len-字符产长度
* 出口参数：无
* 返回值：校验和
* 说    明：无
* 调用方法：无 		   			  
**********************************************************/
uint16 crc16h(char *ptr, uint32 len)        
{ 
	uint8 i; 
	uint16 crc = 0xffff;
	while(len--) 
	{ 
		crc=HIBYTE(crc)^*ptr;
		for(i = 0x80; i != 0; i >>= 1) 
		{   
			if((crc&0x0001) != 0) 
			{
				crc >>= 1;
				crc^=0xa001;
			}         
			else 
			{
				crc>>=1; 
			}                                          
		}
		ptr++; 
	} 
	return(crc); 
}


 
